﻿#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;


//拷贝构造函数
//与构造函数构成函数重载
//要求第一个参数必须是自身类类型的引用

//class Date
//{
//public:
//	//全缺省构造函数
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	//拷贝构造函数
//	//类成员变量全是内置类型且没有指向什么资源，编译器自动生成的拷贝构造就可以完成需要的拷贝，所以不需要我们显示实现拷贝构造
//	Date(const Date& d)
//	{
//		_year = d._year;
//		_month = d._month;
//		_day = d._day;
//	}
//
//	//同时，我们为了防止不小心改变引用对象内置类型的值，const修饰
//	/*Date(Date& d)
//	{
//		//假设我们要判断，又不小心将==写为了=，这时候就会导致引用对象的内置类型被修改，const修饰就会避免这种情况
//		if (_year = d._year)
//		{
//
//		}
//		_year = d._year;
//		_month = d._month;
//		_day = d._day;
//	}*/
//
//	void Print()
//	{
//		cout << _year << "/" << _month << "/" << _day << endl;
//	}
//
//	//由于Date类中的没有申请的资源，不需要实现析构函数
//
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//
//
////自定义类型
////建议参数也用引用，可以避免调用传值传参
//void Func1(Date& d)
//{
//	cout << &d << endl;
//	d.Print();
//}
//
//Date& Func2()
//{
//	//Date tmp(2025, 8, 17);
//	static Date tmp(2025, 8, 17);
//	tmp.Print();
//
//	return tmp;
//}
//
//int main()
//{
//	Date d1(2025, 8, 16);
//	d1.Print();
//
//	//拷贝构造
//	Date d2(d1);//当我们传值传参时，编译器会自动调用拷贝构造函数
//	d2.Print();
//
//	d2 = d1;//编译器会自动转化为Date d2(d1);的形式，并调用拷贝构造函数
//	d2.Print();
//
//	Func1(d1);// 所以这⾥的d1传值传参给d要调用拷贝构造完成拷贝，传引用传参可以较少这⾥的拷贝
//
//	// Func2返回了⼀个局部对象tmp的引⽤作为返回值
//    // Func2函数结束，tmp对象就销毁了，相当于了⼀个野引⽤
//	Date ret = Func2();
//	ret.Print();
//
//	return 0;
//}


class Stack
{
public:
	//全缺省构造函数
	Stack(int n = 4)
	{
		int* tmp = (int*)malloc(sizeof(int) * n);
		if (tmp == nullptr)
		{
			perror("malloc");
			exit(1);
		}
		_arr = tmp;
		_top = 0;
		_capacity = n;
	}

	void Push(int x)//尾插
	{
		if (_top == _capacity)
		{
			int newcapacity = 2 * _capacity;
			int* tmp = (int*)realloc(_arr, sizeof(int) * newcapacity);
			if (tmp == nullptr)
			{
				perror("malloc");
				exit(1);
			}
			_arr = tmp;
			_capacity = newcapacity;
		}
		
		_arr[_top] = x;
		_top++;
	}

	Stack(const Stack& st)
	{
		//先对_arr创建与引用对象指向资源同样大的资源
		int* _arr = (int*)malloc(sizeof(int) * st._capacity);
		{
			if (_arr == nullptr)
			{
				perror("malloc");
				exit(1);
			}
		}
		memcpy(_arr, st._arr, sizeof(int) * _top);

		_top = st._top;
		_capacity = st._capacity;
	}

	//析构函数
	~Stack()
	{
		free(_arr);
		_arr = nullptr;
		_top = _capacity = 0;
	}

private:
	int* _arr;
	int _top;
	int _capacity;
};
//
////传值传参会触发拷贝构造函数，就会为资源开辟空间，赋值（深拷贝）
////此时参数和实例化对象st1指向同一片空间，析构函数调用两次，即对同一片空间释放两次，程序崩溃
//void func1(Stack st)
//{
//	cout << &st << endl;
//
//}
//
////将引用作为参数，即实例化对象st1的别名，传参不再调用拷贝函数
////析构函数仅仅对实例化对象st1的资源释放
//void func2(const Stack& st)
//{
//	cout << &st << endl;
//
//}
//
//
//class MyQueue
//{
//public:
//	//编译器默认生成MyQueue的构造函数调⽤了Stack的构造函数，完成了两个成员(pushst和popst)的初始化；
//	//编译器默认生成MyQueue的析构函数调⽤了Stack的析构函数，释放的两个成员(pushst和popst)内部的资源。
//	//编译器默认生成MyQueue的拷贝构造函数调⽤了Stack的拷贝构造函数，实现了对实例化对象mq2的初始化。
//private:
//	Stack pushst;
//	Stack popst;
//};
//
//int main()
//{
//	Stack st1;
//
//	st1.Push(1);
//	st1.Push(2);
//	st1.Push(3);
//
//	Stack st2(st1);
//
//	func2(st1);
//
//	MyQueue mq1;
//
//	MyQueue mq2(mq1);
//
//	return 0;
//}

////传值返回
//Stack Func()
//{
//	Stack tmp;//实例化对象的同时初始化
//	tmp.Push(1);
//
//	return tmp;//传值返回，产生临时对象，调用拷贝构造函数
//}
//
//
//int main()
//{
//	Stack ret = Func();
//
//	return 0;
//}

//传值引用返回
Stack& func()
{
	static Stack tmp;//实例化对象的同时初始化
	tmp.Push(1);

	return tmp;//传值引用返回，传值引用返回，返回的是返回对象的别名(引用)，没有产生拷贝。
}


int main()
{
	Stack ret = func();

	return 0;
}
